﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace DotNet.Utilities
{
    public static class EnumExtension
    {
        #region 获取枚举描述内容

        public static Attribute GetEnumAttribute(this Enum value,Type attribute)
        {
            var enumType = value.GetType();
            var name = Enum.GetName(enumType, value);
            if (name != null)
            {
                // 获取枚举字段。
                var fieldInfo = enumType.GetField(name);
                if (fieldInfo != null)
                {
                    // 获取描述的属性。
                    var attr = Attribute.GetCustomAttribute(fieldInfo,
                        attribute, false);
                    return attr;
                }
            }
            return null;
        }

        public static T GetEnumAttribute<T>(this Enum value)
        {
            var enumType = value.GetType();
            var name = Enum.GetName(enumType, value);
            if (name != null)
            {
                // 获取枚举字段。
                var fieldInfo = enumType.GetField(name);
                if (fieldInfo != null)
                {
                    // 获取描述的属性。
                    var attr = Attribute.GetCustomAttribute(fieldInfo, typeof(T), false);
                    return (T)(object)attr;
                }
            }
            return default(T);
        }

        /// <summary>
        /// 获取枚举描述内容;
        /// </summary>
        /// <param name="value"></param>
        /// <param name="defaultval"></param>
        /// <returns></returns>
        public static string GetEnumDescription(this Enum value,string defaultval="")
        {
            var attr = GetEnumAttribute(value, typeof (DescriptionAttribute));
            return (attr as DescriptionAttribute)?.Description?? defaultval;
        }

        #endregion

        #region 获取枚举列表

        /// <summary>
        /// 通过枚举对象获取枚举列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static List<T> GetEnumList<T>(this T value)
        {
            var list = new List<T>();
            if (value is Enum)
            {
                var valData =Convert.ToInt32((T)Enum.Parse(typeof(T), value.ToString())) ;
                var tps =Enum.GetValues(typeof (T));

                list.AddRange(from object tp in tps where ((int)Convert.ToInt32((T)Enum.Parse(typeof(T), tp.ToString())) & valData) == valData select (T) tp);
            }

            return list;
        }

        /* 参考：https://www.codenong.com/17123548/ */

        /// <summary>
        /// 通过枚举类型获取枚举列表;
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static List<T> GetEnumList<T>() where T : Enum
        {
            List<T> list = Enum.GetValues(typeof(T)).OfType<T>().ToList();
            return list;
        }

        /* 参考：https://www.codenong.com/105372/ */

        /// <summary>
        /// Gets all items for an enum value.（通过枚举对象获取所有枚举）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static IEnumerable<T> GetAllItems<T>(this Enum value)
        {
            foreach (object item in Enum.GetValues(typeof(T)))
            {
                yield return (T)item;
            }
        }

        /// <summary>
        /// Gets all items for an enum type.（通过枚举类型获取所有枚举）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static IEnumerable<T> GetAllItems<T>() where T : struct
        {
            foreach (object item in Enum.GetValues(typeof(T)))
            {
                yield return (T)item;
            }
        }

        #endregion

        /// <summary>
        /// 将枚举转换为值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T ToValue<T>(this Enum value) where T : struct
        {
            return (T) (object)value;
        }
    }
}
